#include <map>
using namespace std;

#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include "aiot_subdev_api.h"
#include "aiot_mqtt_api.h"
#include "cloud_msg.h"
#include "config.h"
#include "queue.h"
#include "aliyun_proc.h"
#include "nlohmann/json.hpp"
using json = nlohmann::json;

int cloud_online()
{
	json js;
	js["Active"] = "CLOUD_ONLINE_EVENT";
	string tok = js.dump(4);
	send_msg(CTRL_QUEUE, tok.c_str(), tok.size(), 0, 1);
	return 0;
}

int cloud_offline()
{
	json js;
	js["Active"] = "CLOUD_OFFLINE_EVENT";
	string tok = js.dump(4);
	send_msg(CTRL_QUEUE, tok.c_str(), tok.size(), 0, 1);
	return 0;
}

/*******************new json library****************************************/
int ctrl_online(void *mqtt_handle, void *subdev_handle, const json &params)
{
	char buf[1024 * 8];
	while (recv_msg(CLOUD_QUEUE, buf, sizeof(buf), O_NONBLOCK) > 0) {
		printf("discard msg:%s\n", buf);
	}
	if (aly_is_online()) {
		cloud_online();
	} else {
		cloud_offline();
	}
	return 0;
}

int subdev_get_topo(void *mqtt_handle, void *subdev_handle, const json &params)
{
	return aiot_subdev_send_topo_get(subdev_handle);
}

int subdev_register(void *mqtt_handle, void *subdev_handle, const json &devs)
{
	int cnt = 0;
	aiot_subdev_dev_t subdevs[64];
	for (cnt = 0; cnt < devs.size(); cnt++) {
		subdevs[cnt].product_key = (char *)g_conf->self["SubProductionKey"].c_str();
		subdevs[cnt].device_name = (char *)devs[cnt]["Name"].get_ref<const string &>().c_str();
		subdevs[cnt].device_secret = (char *)devs[cnt]["Secret"].get_ref<const string &>().c_str();
		subdevs[cnt].product_secret = (char *)g_conf->self["SubProductionSecret"].c_str();
	}
	return aiot_subdev_send_sub_register(subdev_handle, subdevs, cnt);
}

int subdev_add_topo(void *mqtt_handle, void *subdev_handle, const json &devs)
{
	int cnt = 0;
	aiot_subdev_dev_t subdevs[64];
	for (cnt = 0; cnt < devs.size(); cnt++) {
		subdevs[cnt].product_key = (char *)g_conf->self["SubProductionKey"].c_str();
		subdevs[cnt].device_name = (char *)devs[cnt]["Name"].get_ref<const string &>().c_str();
		subdevs[cnt].device_secret = (char *)devs[cnt]["Secret"].get_ref<const string &>().c_str();
		subdevs[cnt].product_secret = (char *)g_conf->self["SubProductionSecret"].c_str();
	}
	return aiot_subdev_send_topo_add(subdev_handle, subdevs, cnt);
}

int subdev_login(void *mqtt_handle, void *subdev_handle, const json &devs)
{
	int cnt = 0;
	aiot_subdev_dev_t subdevs[64];
	for (cnt = 0; cnt < devs.size(); cnt++) {
		subdevs[cnt].product_key = (char *)g_conf->self["SubProductionKey"].c_str();
		subdevs[cnt].device_name = (char *)devs[cnt]["Name"].get_ref<const string &>().c_str();
		subdevs[cnt].device_secret = (char *)devs[cnt]["Secret"].get_ref<const string &>().c_str();
		subdevs[cnt].product_secret = (char *)g_conf->self["SubProductionSecret"].c_str();
	}
	return aiot_subdev_send_batch_login(subdev_handle, subdevs, cnt);
}

int subdev_logout(void *mqtt_handle, void *subdev_handle, const json &devs)
{
	int cnt = 0;
	string device_name[64], device_secret[64];
	aiot_subdev_dev_t subdevs[64];
	for (cnt = 0; cnt < devs.size(); cnt++) {
		subdevs[cnt].product_key = (char *)g_conf->self["SubProductionKey"].c_str();
		subdevs[cnt].device_name = (char *)devs[cnt]["Name"].get_ptr<const string *>()->c_str();
		subdevs[cnt].device_secret = (char *)devs[cnt]["Secret"].get_ptr<const string *>()->c_str();
		subdevs[cnt].product_secret = (char *)g_conf->self["SubProductionSecret"].c_str();
	}
	return aiot_subdev_send_batch_logout(subdev_handle, subdevs, cnt);
}

int subdev_property_set(void *mqtt_handle, void *subdev_handle, const json &arg)
{
	string id = arg["ID"];
	string subdname = arg["Name"];
	const json &property = arg["Property"];

	int32_t res = 0;
	char pub_topic[256];
	char pub_payload[1024];
	snprintf(pub_topic, sizeof(pub_topic), "/sys/%s/%s/thing/event/property/post", g_conf->self["SubProductionKey"].c_str(), subdname.c_str());
	snprintf(pub_payload, sizeof(pub_payload), "{\"id\":\"%lu\",\"version\":\"1.0\",\"params\":%s}", strtoul(id.c_str(), NULL, 10), property.dump().c_str());
	res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
	if (res < 0) {
		printf("aiot_mqtt_pub failed, res: -0x%04X\n", -res);
	}
	return res;
}

int scene_replay(void *mqtt_handle, void *subdev_handle, const json &args)
{
	const string arg = args.dump();
	int32_t res = 0;
	char pub_topic[256];
	char pub_payload[1024];
	snprintf(pub_topic, sizeof(pub_topic), "/%s/%s/user/scene/issue_reply", g_conf->self["ProductionKey"].c_str(), g_conf->self["DevName"].c_str());
	snprintf(pub_payload, sizeof(pub_payload), "%s", arg.c_str());
	res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
	if (res < 0) {
		printf("aiot_mqtt_pub failed, res: -0x%04X\n", -res);
	}
	return res;
}

int act_replay(void *mqtt_handle, void *subdev_handle, const json &args)
{
	const string arg = args.dump();
	int32_t res = 0;
	char pub_topic[256];
	char pub_payload[1024];
	snprintf(pub_topic, sizeof(pub_topic), "/%s/%s/user/user/issue_reply", g_conf->self["ProductionKey"].c_str(), g_conf->self["DevName"].c_str());
	snprintf(pub_payload, sizeof(pub_payload), "%s", arg.c_str());
	res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
	if (res < 0) {
		printf("aiot_mqtt_pub failed, res: -0x%04X\n", -res);
	}
	return res;
}

int gw_self_property_set(void *mqtt_handle, void *subdev_handle, const json &args)
{
	string id = args["ID"];
	string property = args["Property"];

	int32_t res = 0;
	char pub_topic[256];
	char pub_payload[1024];
	snprintf(pub_topic, sizeof(pub_topic), "/sys/%s/%s/thing/event/property/post", g_conf->self["ProductionKey"].c_str(), g_conf->self["DevName"].c_str());
	snprintf(pub_payload, sizeof(pub_payload), "{\"id\":\"%lu\",\"version\":\"1.0\",\"params\":%s}", strtoul(id.c_str(), NULL, 10), property.c_str());
	res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
	if (res < 0) {
		printf("aiot_mqtt_pub failed, res: -0x%04X\n", -res);
	}
	return res;
}

using event_proc = int (*)(void *, void *, const json &arg);
map<string, event_proc> event_route = {
	/*
	interface
	*/
	{ "CTRL_ONLINE_EVENT", ctrl_online },
	{ "SUBDEV_GET_TOPO", subdev_get_topo },
	{ "SUBDEV_REGISTER", subdev_register },
	{ "SUBDEV_ADD_TOPO", subdev_add_topo },
	{ "SUBDEV_LOGIN", subdev_login },

	{ "SUBDEV_LOGOUT", subdev_logout },
	{ "SET_SUBDEV_PROPERTY", subdev_property_set },
	{ "SCENE_REPLAY", scene_replay },
	{ "ACT_REPLAY", act_replay },
	{ "GW_SELF_PROPERTY_SET", gw_self_property_set }
};

int cloud_msg_proc(const char *msg, void *mqtt_handle, void *subdev_handle)
{
	nlohmann::json js = json::parse(msg, msg + strlen(msg), nullptr, 0);
	if (js.is_discarded()) {
		return -1;
	}
	string active = js["Active"];
	nlohmann::json &arg = js["Params"];
	if (event_route[active]) {
		event_route[active](mqtt_handle, subdev_handle, arg);
		return 0;
	}

	return -1;
}
